package org.springframework.security.core.context;

import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Constructor;
import java.util.function.Supplier;

/**
 * @author Dillon
 * @date 2024/6/28
 * @slogan 致敬大师 致敬未来的你
 * @desc springSecurity 管理登录成功session封装策略类
 * 默认策略实现类  ThreadLocalSecurityContextHolderStrategy
 */
public class SecurityContextHolder {

	/**
	 * 标记策略实现类 threadLocal
	 */
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";

	/**
	 * 标记策略实现类 inheritableThreadLocal
	 */
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";

	/**
	 * 标记策略实现类 global
	 */
	public static final String MODE_GLOBAL = "MODE_GLOBAL";

	/**
	 * 标记策略实现类 自定义策略实现类名称
	 */
	private static final String MODE_PRE_INITIALIZED = "MODE_PRE_INITIALIZED";

	/**
	 * security 默认的策略字符串
	 */
	public static final String SYSTEM_PROPERTY = "spring.security.strategy";

	/**
	 * 从系统配置中获取Security策略配置
	 */
	private static String strategyName = System.getProperty(SYSTEM_PROPERTY);

	/**
	 * 自定义策略实现类
	 */
	private static SecurityContextHolderStrategy strategy;

	/**
	 * 初始化次数
	 */
	private static int initializeCount = 0;

	/**
	 * 初始化方法
	 */
	static {
		initialize();
	}

	/**
	 * 初始化策略
	 */
	private static void initialize() {
		initializeStrategy();
		initializeCount++;
	}

	/**
	 * 初始化策略
	 */
	private static void initializeStrategy() {
		// 判断是否设置了自定义策略，如果设置了自定义策略，那么必须初始化项目时，调用该策略方法，设置策略实现类
		if (MODE_PRE_INITIALIZED.equals(strategyName)) {
			Assert.state(strategy != null, "When using " + MODE_PRE_INITIALIZED + ", setContextHolderStrategy must be called with the fully constructed strategy");
			return;
		}
		// 如果未设置，使用默认策略 threadLocal
		if (!StringUtils.hasText(strategyName)) {
			strategyName = MODE_THREADLOCAL;
		}
		// 实例化策略判断
		strategy = switch (strategyName) {
			case MODE_THREADLOCAL -> new ThreadLocalSecurityContextHolderStrategy();
			case MODE_INHERITABLETHREADLOCAL -> new InheritableThreadLocalSecurityContextHolderStrategy();
			case MODE_GLOBAL -> new GlobalSecurityContextHolderStrategy();
			default -> customStrategy();
		};
	}

	/**
	 * 尝试通过反射实例化自定义策略
	 *
	 * @return 自定义创建反射类
	 */
	private static SecurityContextHolderStrategy customStrategy() {
		try {
			Class<?> clazz = Class.forName(strategyName);
			Constructor<?> customStrategy = clazz.getConstructor();
			return (SecurityContextHolderStrategy) customStrategy.newInstance();
		} catch (Exception ex) {
			ReflectionUtils.handleReflectionException(ex);
		}
		return null;
	}

	/**
	 * 清除缓存
	 */
	public static void clearContext() {
		strategy.clearContext();
	}

	/**
	 * 获取缓存
	 *
	 * @return SecurityContext
	 */
	public static SecurityContext getContext() {
		return strategy.getContext();
	}

	/**
	 * 获取一个延时加载的缓存
	 *
	 * @return 延时加载缓存
	 */
	public static Supplier<SecurityContext> getDeferredContext() {
		return strategy.getDeferredContext();
	}

	/**
	 * 获取该类的初始化次数，用于排除故障使用
	 *
	 * @return 该类初始化次数
	 */
	public static int getInitializeCount() {
		return initializeCount;
	}

	/**
	 * 设置缓存
	 *
	 * @param context 缓存
	 */
	public static void setContext(SecurityContext context) {
		strategy.setContext(context);
	}

	/**
	 * 设置缓存提供者
	 *
	 * @param deferredContext 缓存提供者
	 */
	public static void setDeferredContext(Supplier<SecurityContext> deferredContext) {
		strategy.setDeferredContext(deferredContext);
	}

	/**
	 * 设置策略名称 每设置一次策略名称，则初始化一次缓存
	 *
	 * @param strategyName 策略名称
	 */
	public static void setStrategyName(String strategyName) {
		SecurityContextHolder.strategyName = strategyName;
		initialize();
	}

	/**
	 * 设置自定义缓存策略实现类
	 *
	 * @param strategy 策略实现类
	 */
	public static void setContextHolderStrategy(SecurityContextHolderStrategy strategy) {
		Assert.notNull(strategy, "securityContextHolderStrategy cannot be null");
		SecurityContextHolder.strategyName = MODE_PRE_INITIALIZED;
		SecurityContextHolder.strategy = strategy;
		initialize();
	}

	/**
	 * 获取当前缓存策略实现类
	 *
	 * @return 策略实现类
	 */
	public static SecurityContextHolderStrategy getContextHolderStrategy() {
		return strategy;
	}

	/**
	 * 创建一个空的缓存
	 *
	 * @return 空缓存
	 */
	public static SecurityContext createEmptyContext() {
		return strategy.createEmptyContext();
	}

	/**
	 * toString
	 *
	 * @return toString
	 */
	@Override
	public String toString() {
		return "SecurityContextHolder[strategy='" + strategy.getClass().getSimpleName() + "'; initializeCount="
				+ initializeCount + "]";
	}

}
